from random import choice

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q
from django.conf import settings

from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from rest_framework import mixins
from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler
from rest_framework import permissions  # 权限
from rest_framework import authentication  # 身份认证
from rest_framework_jwt.authentication import JSONWebTokenAuthentication  # jwt

from .serializers import SmsSerializers, UserRegSerializer, UserDetailSerializer
from .models import VerifyCode  # 验证码保存到数据库
from utils.yunpian import YunPian

User = get_user_model()


class CustomBackend(ModelBackend):
    """
    自定义用户验证
    """

    def authenticate(self, username=None, password=None, **kwargs):
        """
        自定义用户验证
      """
        try:
            user = User.objects.get(Q(username=username) | Q(mobile=username))
            if user.check_password(password):  # check_password()对明文密码进行加密
                return user
        except Exception as e:
            return None


class SmsCodeViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    """发送短信验证码"""
    serializer_class = SmsSerializers

    def generate_code(self):
        """
        生成四位数字的验证码
        :return:
        """
        seeds = "1234567890"
        random_str = []
        for i in range(4):
            random_str.append(choice(seeds))
        return "".join(random_str)

    # 重写create方法
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        mobile = serializer.validated_data["mobile"]
        # 云片网发送短信验证码
        rest_yun = YunPian(settings.APIKEY)
        code = self.generate_code()
        sms_status = rest_yun.send_sms(code=code, mobile=mobile)
        if sms_status["code"] != 0:
            return Response({
                "mobile": sms_status["msg"]
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile": mobile
            }, status=status.HTTP_201_CREATED)


class UserViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """用户注册"""
    serializer_class = UserRegSerializer
    queryset = User.objects.all()
    authentication_classes = [authentication.SessionAuthentication, JSONWebTokenAuthentication]

    # 重写get_serializer_class()方法，使用不同的serializers.注册使用UserRegSerializer,查看用户详情使用UserDetailSerializer,其它情况都返回UserDetailSerializer
    def get_serializer_class(self):
        if self.action == "retrieve":
            return UserDetailSerializer
        elif self.action == "create":
            return UserRegSerializer
        return UserDetailSerializer

    # permission_classes = [permissions.IsAuthenticated]  # 必须用户登录后才能访问,但是注册需要排除。所以这种方式不适合。
    # 权限控制2，重写get_permissions()方法,实现用户注册不需要登录，其它操作都需要登录。
    def get_permissions(self):
        if self.action == "retrieve":
            return [permissions.IsAuthenticated()]
        elif self.action == "create":
            return []
        return []

    # 注册完成后直接登录
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 根据user生成token
        user_obj = self.perform_create(serializer)
        re_dict = serializer.data
        payload = jwt_payload_handler(user_obj)
        re_dict["token"] = jwt_encode_handler(payload)
        re_dict["name"] = user_obj.name if user_obj.name else user_obj.username
        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    def get_object(self):
        """
        重载get_object返回当前用户
        :return:
        """
        return self.request.user

    # 生成用户token的时候必须获取到user，所以要重写perform_create()方法
    def perform_create(self, serializer):
        return serializer.save()
